home *** CD-ROM | disk | FTP | other *** search
- From: reynolds@uunet.uu.net@hsvpmi.UUCP
- Newsgroups: comp.sources.misc
- Subject: v02i068: UN*X pipes for MSDOS
- Message-ID: <7471@ncoast.UUCP>
- Date: 5 Mar 88 23:09:36 GMT
- Approved: allbery@ncoast.UUCP
-
- Comp.sources.misc: Volume 2, Issue 68
- Submitted-By: "A. Nonymous" <reynolds@uunet.uu.net@hsvpmi.UUCP>
- Archive-Name: msdos-pipes
-
- [I'm not so sure I see the point of this.... ++bsa]
-
- Here is an MS-DOS version of the UN*X popen(3S) routine, inspired
- by an off-the-cuff article from the net (no, I don't have the
- reference... :-). It works under TURBO-C, and is compatible with
- the MKS Toolkit (but it works fine without it).
-
- Compile with the -DDEMO switch to generate a demo program used
- like this:
-
- popen command ....
-
- to run 'command ...' from a read-mode pipe. If the shell
- environment variable SHELL is set, that program is used;
- otherwise the variable COMSPEC is used; failing all that,
- COMMAND.COM in the current working directory is used.
-
- Caveat programme...
-
- ---------
- Tom Reynolds voice: (205) 721-1200 x 303
- Phoenix microsystems, inc. uucp: ..!uunet!ingr!hsvpmi!reynolds
- 991 Discovery Drive
- Huntsville, AL 35806 "First curse the darkness, then light the candle"
-
- o / o / o / o / o / o / o /
- ---- x ------- x ------- x ------- x ------- x ------- x ------- x -------
- o \ o \ o \ o \ o \ o \ o \
- #! /bin/sh
- # This is a shell archive, meaning:
- # 1. Remove everything above the #! /bin/sh line.
- # 2. Save the resulting text in a file.
- # 3. Execute the file with /bin/sh (not csh) to create:
- # getswitch.c
- # makefile
- # popen.c
- # popen.h
- # turboc.cfg
- # This archive created: Wed Mar 2 17:24:28 1988
- export PATH; PATH=/bin:/usr/bin:$PATH
- echo shar: "extracting 'getswitch.c'" '(274 characters)'
- if test -f 'getswitch.c'
- then
- echo shar: "will not over-write existing file 'getswitch.c'"
- else
- sed 's/^ X//' << \SHAR_EOF > 'getswitch.c'
- X#include <stdio.h>
- X#include <dos.h>
- X
- Xstatic char SW = 0; /* DOS switch character, either '-' or '/' */
- X
- Xint
- Xgetswitch()
- X{
- X if (SW == 0) {
- X /* get SW using dos call 0x37 */
- X _AX = 0x3700;
- X geninterrupt(0x21);
- X SW = _DL;
- X }
- X return( SW & 0xFF );
- X}
- SHAR_EOF
- if test 274 -ne "`wc -c < 'getswitch.c'`"
- then
- echo shar: "error transmitting 'getswitch.c'" '(should have been 274 characters)'
- fi
- fi
- echo shar: "extracting 'makefile'" '(226 characters)'
- if test -f 'makefile'
- then
- echo shar: "will not over-write existing file 'makefile'"
- else
- sed 's/^ X//' << \SHAR_EOF > 'makefile'
- Xpopen.exe: popen.obj getswitch.obj
- X cc -epopen popen.obj getswitch.obj
- X
- Xpopen.obj: popen.c
- X cc -c -DDEMO popen.c
- X
- Xclean:
- X rm -f *.obj core *.map
- X
- Xclobber: clean
- X rm -f *.exe install
- X
- Xinstall:
- X cc -c popen.c
- X @echo What next?
- SHAR_EOF
- if test 226 -ne "`wc -c < 'makefile'`"
- then
- echo shar: "error transmitting 'makefile'" '(should have been 226 characters)'
- fi
- fi
- echo shar: "extracting 'popen.c'" '(9895 characters)'
- if test -f 'popen.c'
- then
- echo shar: "will not over-write existing file 'popen.c'"
- else
- sed 's/^ X//' << \SHAR_EOF > 'popen.c'
- X/* popen/pclose:
- X *
- X * simple MS-DOS piping scheme to imitate UNIX pipes
- X */
- X
- X#include <stdio.h>
- X#include <ctype.h>
- X#include <alloc.h>
- X#include <string.h>
- X#include <errno.h>
- X#include <setjmp.h>
- X#include <process.h>
- X
- X#include "popen.h"
- X
- Xextern char *getenv( char * );
- X
- X#ifndef _NFILE
- X# define _NFILE OPEN_MAX /* Number of open files */
- X#endif _NFILE
- X
- X#define READIT 1 /* Read pipe */
- X#define WRITEIT 2 /* Write pipe */
- X
- Xstatic char *prgname[ _NFILE ]; /* program name if write pipe */
- Xstatic int pipetype[ _NFILE ]; /* 1=read 2=write */
- Xstatic char *pipename[ _NFILE ]; /* pipe file name */
- X
- X/*
- X *------------------------------------------------------------------------
- X * stoupper: Convert string to uppercase (in place)
- X *------------------------------------------------------------------------
- X */
- X
- Xstatic void
- Xstoupper( s )
- Xchar *s;
- X{
- X int c;
- X for( ; (c = *s) != '\0'; ++s ) {
- X if( islower( c ) ) *s = _toupper( c );
- X }
- X}
- X
- X/*
- X *------------------------------------------------------------------------
- X * strsave: Copy string into malloc'ed memory and return address
- X *------------------------------------------------------------------------
- X */
- X
- Xstatic char *
- Xstrsave( s )
- Xchar *s;
- X{
- X char *sp = malloc( strlen( s ) + 1 );
- X if( sp != (char *) NULL ) (void) strcpy( sp, s );
- X return( sp );
- X}
- X
- X/*
- X *------------------------------------------------------------------------
- X * strfree: Returm strsave'd string memory
- X *------------------------------------------------------------------------
- X */
- X
- Xstatic void
- Xstrfree( s )
- Xchar *s;
- X{
- X if( s != (char *) NULL ) free( s );
- X}
- X
- X/*
- X *------------------------------------------------------------------------
- X * run: Execute command via SHELL or COMSPEC
- X *------------------------------------------------------------------------
- X */
- X
- Xstatic int
- Xrun( command )
- Xchar *command;
- X{
- X jmp_buf panic; /* How to recover from errors */
- X int lineno; /* Line number where panic happened */
- X char *shell; /* Command processor */
- X char *s = (char *) NULL; /* Holds the command */
- X int s_is_malloced = 0; /* True if need to free 's' */
- X static char *command_com = "COMMAND.COM";
- X int status; /* Return codes */
- X char *shellpath; /* Full command processor path */
- X char *bp; /* Generic string pointer */
- X static char dash_c[ 3 ] = { '?', 'c', '\0' };
- X if( (lineno = setjmp( panic )) != 0 ) {
- X int E = errno;
- X#ifdef DEMO
- X fprintf( stderr, "RUN panic on line %d: %d\n", lineno, E );
- X#endif DEMO
- X if( s_is_malloced && (s != (char *) NULL) ) strfree( s );
- X errno = E;
- X return( -1 );
- X }
- X if( (s = strsave( command )) == (char *) NULL ) longjmp( panic, __LINE__ );
- X /* Determine the command processor */
- X if( ((shell = getenv( "SHELL" )) == (char *) NULL) &&
- X ((shell = getenv( "COMSPEC" )) == (char *) NULL) ) shell = command_com;
- X stoupper( shell );
- X shellpath = shell;
- X /* Strip off any leading backslash directories */
- X shell = strrchr( shellpath, '\\' );
- X if( shell != (char *) NULL ) ++shell;
- X else shell = shellpath;
- X /* Strip off any leading slash directories */
- X bp = strrchr( shell, '/' );
- X if( bp != (char *) NULL ) shell = ++bp;
- X if( strcmp( shell, command_com ) != 0 ) {
- X /* MKS Shell needs quoted argument */
- X char *bp;
- X if( (bp = s = malloc( strlen( command ) + 3 )) == (char *) NULL )
- X longjmp( panic, __LINE__ );
- X *bp++ = '\'';
- X while( (*bp++ = *command++) != '\0' );
- X *(bp - 1) = '\'';
- X *bp = '\0';
- X s_is_malloced = 1;
- X } else s = command;
- X dash_c[ 0 ] = getswitch();
- X /* Run the program */
- X#ifdef DEMO
- X fprintf( stderr, "Running: (%s) %s %s %s\n", shellpath, shell, dash_c, s );
- X#endif DEMO
- X status = spawnl( P_WAIT, shellpath, shell, dash_c, s, (char *) NULL );
- X if( s_is_malloced ) free( s );
- X return( status );
- X}
- X
- X/*
- X *------------------------------------------------------------------------
- X * uniquepipe: returns a unique file name
- X *------------------------------------------------------------------------
- X */
- X
- Xstatic char *
- Xuniquepipe()
- X{
- X static char name[ 14 ];
- X static short int num = 0;
- X (void) sprintf( name, "pipe%05d.tmp", num++ );
- X return( name );
- X}
- X
- X/*
- X *------------------------------------------------------------------------
- X * resetpipe: Private routine to cancel a pipe
- X *------------------------------------------------------------------------
- X */
- X
- Xstatic void
- Xresetpipe( fd )
- Xint fd;
- X{
- X char *bp;
- X if( (fd >= 0) && (fd < _NFILE) ) {
- X pipetype[ fd ] = 0;
- X if( (bp = pipename[ fd ]) != (char *) NULL ) {
- X (void) unlink( bp );
- X strfree( bp );
- X pipename[ fd ] = (char *) NULL;
- X }
- X if( (bp = prgname[ fd ]) != (char *) NULL ) {
- X strfree( bp );
- X prgname[ fd ] = (char *) NULL;
- X }
- X }
- X}
- X
- X/*
- X *------------------------------------------------------------------------
- X * popen: open a pipe
- X *------------------------------------------------------------------------
- X */
- X
- XFILE *popen( prg, type )
- Xchar *prg; /* The command to be run */
- Xchar *type; /* "w" or "r" */
- X{
- X FILE *p = (FILE *) NULL; /* Where we open the pipe */
- X int ostdin; /* Where our stdin is now */
- X int pipefd = -1; /* fileno( p ) -- for convenience */
- X char tmpfile[ BUFSIZ ]; /* Holds name of pipe file */
- X char *tmpdir; /* Points to directory prefix of pipe */
- X jmp_buf panic; /* Where to go if there's an error */
- X int lineno; /* Line number where panic happened */
- X /* Find out where we should put temporary files */
- X if( (tmpdir = getenv( "TMPDIR" )) == (char *) NULL )
- X tmpdir = getenv( "TMP" );
- X if( tmpdir != (char *) NULL ) {
- X /* Use temporary directory if available */
- X (void) strcpy( tmpfile, tmpdir );
- X (void) strcat( tmpfile, "/" );
- X } else *tmpfile = '\0';
- X /* Get a unique pipe file name */
- X (void) strcat( tmpfile, uniquepipe() );
- X if( (lineno = setjmp( panic )) != 0 ) {
- X /* An error has occurred, so clean up */
- X int E = errno;
- X#ifdef DEMO
- X fprintf( stderr, "POPEN panic on line %d: %d\n", lineno, E );
- X#endif DEMO
- X if( p != (FILE *) NULL ) (void) fclose( p );
- X resetpipe( pipefd );
- X errno = E;
- X return( (FILE *) NULL );
- X }
- X if( strcmp( type, "w" ) == 0 ) {
- X /* for write style pipe, pclose handles program execution */
- X if( (p = fopen( tmpfile, "w" )) != (FILE *) NULL ) {
- X pipefd = fileno( p );
- X pipetype[ pipefd ] = WRITEIT;
- X pipename[ pipefd ] = strsave( tmpfile );
- X prgname[ pipefd ] = strsave( prg );
- X if( !pipename[ pipefd ] || !prgname[ pipefd ] ) longjmp( panic, __LINE__ );
- X }
- X } else if( strcmp( type, "r" ) == 0 ) {
- X /* read pipe must create tmp file, set up stdout to point to the temp
- X * file, and run the program. note that if the pipe file cannot be
- X * opened, it'll return a condition indicating pipe failure, which is
- X * fine.
- X */
- X if( (p = fopen( tmpfile, "w" )) != (FILE *) NULL ) {
- X int ostdout;
- X pipefd = fileno( p );
- X pipetype[ pipefd ]= READIT;
- X if( (pipename[ pipefd ] = strsave( tmpfile )) == (char *) NULL )
- X longjmp( panic, __LINE__ );
- X /* Redirect stdin for the new command */
- X ostdout = dup( fileno( stdout ) );
- X if( dup2( fileno( stdout ), pipefd ) < 0 ) {
- X int E = errno;
- X (void) dup2( fileno( stdout ), ostdout );
- X errno = E;
- X longjmp( panic, __LINE__ );
- X }
- X if( run( prg ) != 0 ) longjmp( panic, __LINE__ );
- X if( dup2( fileno( stdout ), ostdout ) < 0 ) longjmp( panic, __LINE__ );
- X if( fclose( p ) < 0 ) longjmp( panic, __LINE__ );
- X if( (p = fopen( tmpfile, "r" )) == (FILE *) NULL ) longjmp( panic, __LINE__ );
- X }
- X } else {
- X /* screwy call or unsupported type */
- X errno = EINVFNC;
- X longjmp( panic, __LINE__ );
- X }
- X return( p );
- X}
- X
- X/* close a pipe */
- X
- Xint
- Xpclose( p )
- XFILE *p;
- X{
- X int pipefd = -1; /* Fildes where pipe is opened */
- X int ostdout; /* Where our stdout points now */
- X int ostdin; /* Where our stdin points now */
- X jmp_buf panic; /* Context to return to if error */
- X int lineno; /* Line number where panic happened */
- X if( (lineno = setjmp( panic )) != 0 ) {
- X /* An error has occurred, so clean up and return */
- X int E = errno;
- X#ifdef DEMO
- X fprintf( stderr, "POPEN panic on line %d: %d\n", lineno, E );
- X#endif DEMO
- X if( p != (FILE *) NULL ) (void) fclose( p );
- X resetpipe( pipefd );
- X errno = E;
- X return( -1 );
- X }
- X pipefd = fileno( p );
- X if( fclose( p ) < 0 ) longjmp( panic, __LINE__ );
- X switch( pipetype[ pipefd ] ) {
- X case WRITEIT:
- X /* open the temp file again as read, redirect stdin from that
- X * file, run the program, then clean up.
- X */
- X if( (p = fopen( pipename[ pipefd ],"r" )) == (FILE *) NULL )
- X longjmp( panic, __LINE__ );
- X ostdin = dup( fileno( stdin ));
- X if( dup2( fileno( stdin ), fileno( p ) ) < 0 ) longjmp( panic, __LINE__ );
- X if( run( prgname[ pipefd ] ) != 0 ) longjmp( panic, __LINE__ );
- X if( dup2( fileno( stdin ), ostdin ) < 0 ) longjmp( panic, __LINE__ );
- X if( fclose( p ) < 0 ) longjmp( panic, __LINE__ );
- X resetpipe( pipefd );
- X break;
- X case READIT:
- X /* close the temp file and remove it */
- X resetpipe( pipefd );
- X break;
- X default:
- X errno = EINVFNC;
- X longjmp( panic, __LINE__ );
- X /*NOTREACHED*/
- X }
- X return( 0 );
- X}
- X
- X#ifdef DEMO
- Xint
- Xmain( argc, argv )
- Xint argc;
- Xchar **argv;
- X{
- X FILE *pipe;
- X char buf[ BUFSIZ ];
- X int n;
- X *buf = '\0';
- X for( n = 1; n < argc; ++n ) {
- X (void) strcat( buf, argv[ n ] );
- X (void) strcat( buf, " " );
- X }
- X if( (pipe = popen( buf, "r" )) != (FILE *) NULL ) {
- X while( fgets( buf, sizeof( buf ), pipe ) != (char *) NULL )
- X (void) fputs( buf, stdout );
- X if( pclose( pipe ) != 0 ) fprintf( stderr, "error closing pipe!\n" );
- X } else fprintf( stderr, "it didn't work!\n" );
- X exit( 0 );
- X /*NOTREACHED*/
- X}
- X#endif DEMO
- SHAR_EOF
- if test 9895 -ne "`wc -c < 'popen.c'`"
- then
- echo shar: "error transmitting 'popen.c'" '(should have been 9895 characters)'
- fi
- fi
- echo shar: "extracting 'popen.h'" '(67 characters)'
- if test -f 'popen.h'
- then
- echo shar: "will not over-write existing file 'popen.h'"
- else
- sed 's/^ X//' << \SHAR_EOF > 'popen.h'
- Xextern FILE *popen( char *, char * );
- Xextern int pclose( FILE * );
- SHAR_EOF
- if test 67 -ne "`wc -c < 'popen.h'`"
- then
- echo shar: "error transmitting 'popen.h'" '(should have been 67 characters)'
- fi
- fi
- echo shar: "extracting 'turboc.cfg'" '(76 characters)'
- if test -f 'turboc.cfg'
- then
- echo shar: "will not over-write existing file 'turboc.cfg'"
- else
- sed 's/^ X//' << \SHAR_EOF > 'turboc.cfg'
- X-LC:\TURBOC\LIB -IC:\TURBOC\INCLUDE -IC:\TURBOC\INCLUDE\SYS -ms -DTURBOC -M
- SHAR_EOF
- if test 76 -ne "`wc -c < 'turboc.cfg'`"
- then
- echo shar: "error transmitting 'turboc.cfg'" '(should have been 76 characters)'
- fi
- fi
- exit 0
- # End of shell archive
-